<?php

// ------------------------------------------------------------------------
// |@Author       : Jarmin <edshop@qq.com>
// |@----------------------------------------------------------------------
// |@Date         : 2025-04-19 19:29:39
// |@----------------------------------------------------------------------
// |@LastEditTime : 2025-04-29 14:02:36
// |@----------------------------------------------------------------------
// |@LastEditors  : Jarmin <jarmin@ladmin.cn>
// |@----------------------------------------------------------------------
// |@Description  : Token仓储类
// |@----------------------------------------------------------------------
// |@FilePath     : Token.php
// |@----------------------------------------------------------------------
// |@Copyright (c) 2025 http://www.ladmin.cn   All rights reserved.
// ------------------------------------------------------------------------

namespace think\admin\repository;

use think\admin\Repository;

/**
 * Token仓储类
 * Class Token
 * @package app\admin\repository
 */
class Token extends Repository
{
    /**
     * 保存Token信息
     *
     * @param array $data Token数据
     * @return bool 是否保存成功
     */
    public function saveToken(array $data): bool
    {
        return $this->modelToken->save($data);
    }

    /**
     * 验证Token是否有效
     *
     * @param string $jti Token唯一标识
     * @return bool 是否有效
     */
    public function isTokenValid(string $jti): bool
    {
        $token = $this->modelToken
            ->where('jti', $jti)
            ->where('is_revoked', 0)
            ->where('expired_at', '>', date('Y-m-d H:i:s'))
            ->find();

        return (bool)$token;
    }

    /**
     * 吊销Token
     *
     * @param string $jti Token唯一标识
     * @param int $userId 用户ID
     * @return bool 是否吊销成功
     */
    public function revokeToken(string $jti, int $userId): bool
    {
        return $this->modelToken
            ->where('jti', $jti)
            ->where('user_id', $userId)
            ->update(['is_revoked' => 1]);
    }

    /**
     * 吊销用户所有Token
     *
     * @param int $userId 用户ID
     * @return bool 是否吊销成功
     */
    public function revokeAllUserTokens(int $userId): bool
    {
        return $this->modelToken
            ->where('user_id', $userId)
            ->update(['is_revoked' => 1]);
    }

    /**
     * 吊销除当前外的其他Token
     *
     * @param int $userId 用户ID
     * @param string $currentJti 当前JTI
     * @return int 吊销的Token数量
     */
    public function revokeOtherTokens(int $userId, string $currentJti): int
    {
        return $this->modelToken
            ->where('user_id', $userId)
            ->where('jti', '<>', $currentJti)
            ->where('is_revoked', 0)
            ->update(['is_revoked' => 1]);
    }

    /**
     * 获取用户活跃Token列表
     *
     * @param int $userId 用户ID
     * @return array Token列表
     */
    public function getUserActiveTokens(int $userId): array
    {
        $tokens = $this->modelToken
            ->where('user_id', $userId)
            ->where('is_revoked', 0)
            ->where('expired_at', '>', date('Y-m-d H:i:s'))
            ->field('id,device,ip,created_at,expired_at,type')
            ->select();

        return $tokens ? $tokens->toArray() : [];
    }

    /**
     * 清理过期Token
     *
     * @return int 清理数量
     */
    public function cleanExpiredTokens(): int
    {
        return $this->modelToken
            ->where('expired_at', '<', date('Y-m-d H:i:s'))
            ->delete(true);
    }
    
    /**
     * 清理长时间未使用的Token
     *
     * @param int $days 未使用天数
     * @return int 清理数量
     */
    public function cleanUnusedTokens(int $days = 30): int
    {
        return $this->modelToken
            ->where('last_used_at', '<', date('Y-m-d H:i:s', strtotime("-{$days} days")))
            ->where('is_revoked', 0)
            ->update(['is_revoked' => 1]);
    }

    /**
     * 更新Token最后使用时间
     *
     * @param string $jti Token唯一标识
     * @return bool 是否更新成功
     */
    public function updateLastUsedTime(string $jti): bool
    {
        return $this->modelToken
            ->where('jti', $jti)
            ->update(['last_used_at' => date('Y-m-d H:i:s')]);
    }
}
